﻿using NModbus;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace AnalogInput
{
    public class DeviceComm
    {
        public string Address { get; set; }
        public int Port { get; set; }
        public int Timeout { get; set; } = 3000;
        private IModbusMaster master;
        CancellationTokenSource cansrc = new CancellationTokenSource();
        public event Action<ConcurrentDictionary<int, float>> AnalogEvent;
        private ConcurrentDictionary<int, float> pairs=new ConcurrentDictionary<int, float>();
        public DeviceComm() { }
        public DeviceComm(string ip,int port)
        {
            Address = ip;
            Port = port;
        }
        /// <summary>
        /// 准备就绪
        /// </summary>
        public async void Ready()
        {
            const int retryDelayMilliseconds = 2000;
            const int maxRetries = int.MaxValue;
            int retryCount = 0;
            await Task.Factory.StartNew(async () =>
            {
                while (!cansrc.IsCancellationRequested)
                {
                    try
                    {
                        using (TcpClient tcpClient = new TcpClient(Address, Port))
                        {
                            ModbusFactory factory = new ModbusFactory();
                            master = factory.CreateMaster(tcpClient);
                            master.Transport.ReadTimeout = Timeout;
                            await ReadDataAsync(master);
                            retryCount = 0;
                        }
                        Thread.Sleep(50);
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine($"Error reading Modbus data at {DateTime.Now}: {ex.Message}");
                        retryCount++;
                        if (retryCount >= maxRetries)
                        {
                            Console.WriteLine($"Failed to read Modbus data after {maxRetries} attempts. Exiting loop.");
                            break;
                        }
                        await Task.Delay(retryDelayMilliseconds);
                    }
                }
            });
            
        }
        /// <summary>
        /// 停止监控
        /// </summary>
        public void Stop()
        {
            cansrc.Cancel();
        }
        /// <summary>
        /// 读取值
        /// </summary>
        /// <param name="master"></param>
        /// <returns></returns>
        private async Task ReadDataAsync(IModbusMaster master)
        {
            try
            {
                pairs?.Clear();
                ushort startAddressAIN1 = 0;
                ushort numRegistersAIN1 = 32;
                ushort[] ainData = await master.ReadInputRegistersAsync(254, startAddressAIN1, numRegistersAIN1);
                for (int i = 0; i < ainData.Length; i++)
                {
                    pairs.TryAdd(i,(float)(ainData[i]*0.001));
                }
                AnalogEvent?.Invoke(pairs);
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
        }
        /// <summary>
        /// 写入值
        /// </summary>
        /// <param name="values">8个数据</param>
        /// <returns></returns>
        public async Task WriteValueAsync(ushort[] values)
        {
            await master.WriteMultipleRegistersAsync(1,0,values);
        }
    }
}
